/*************************************************************************
	> File Name: 日期相差天数.cpp
	> Author: ma6174
	> Mail: ma6174@163.com 
	> Created Time: Sun 02 Jun 2013 01:28:20 AM CST
 ************************************************************************/

#include<iostream>
using namespace std;

#define STR(exp) #exp

#define NORMAL_YEAR 365
#define LEAP_YEAR 366

struct Date {
	Date(int y, int m, int d) :
		year(y), month(m), day(d) {
		}
	int year;
	int month;
	int day;
};

bool
IsLeapYear(int year) {
	return (year % 4 == 0 || year % 100 == 0) && (year % 400 != 0);
}

ostream &
operator << (ostream &os, const Date &d) {
	os << d.year << "年"
		<< d.month << "月"
		<< d.day << "日";
	return os;
}

bool
operator < (const Date &d1, const Date &d2) {
	if (d1.year < d2.year)
		return true;
	if (d1.year > d2.year)
		return false;

	//d1.year == d2.year
	if (d1.month < d2.month)
		return true;
	if (d1.month > d2.month)
		return false;

	//d1.month == d2.month
	if (d1.day < d2.day)
		return true;
	if (d1.day > d2.day)
		return false;

	//d1.day == d2.day
	return false;
}

/*
 * 根据一个日期，返回它是当年的第n天
 * 如：2013年1月1日 是当年的第1天
 */
int
TheNthDayOfYear(const Date &d) {
	int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	if (IsLeapYear(d.year))
		days[1] = 29;
	int daysCount = 0;
	for (int i = 0; i < d.month-1; ++i)
		daysCount += days[i];
	daysCount += d.day;

	return daysCount;
}

/*
 * 返回一个日期之后nthdays天之后的日期
 * 例如：2013年6月2号之后0天是6月2号
 *		 2013年6月2号之后1天是6月3号
 */
Date
TheNthDaysAfter(const Date &date, int nthdays) {
	//转化为当年的1月1号向后n天
	int daysCount= TheNthDayOfYear(date) - 1;
	daysCount+= nthdays;

	//从当年的1月1号开始向后算
	int y = date.year;
	int m = 1;
	int d = 1;

	for (; ; y++) {
		if (IsLeapYear(y) && daysCount >= LEAP_YEAR) {
			daysCount -= LEAP_YEAR;
		} 
		else if (daysCount > NORMAL_YEAR) {
			daysCount -= NORMAL_YEAR;
		} else {
			break;
		}
	}
	int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	if (IsLeapYear(y)) 
		days[1] = 29; 
	while(daysCount > days[m-1]) {
		daysCount -= days[m-1]; 
		++m;
	}
	d = daysCount;
	return Date(y, m, d+1);
}

Date
TheNthDayBefore(const Date &date, int nthdays) {
	//date是当年的第几天
	//-1是因为TheNthDayOfYear返回天数从1开始
	int daysCount = TheNthDayOfYear(date) - 1;
	Date new_date(date.year, 1, 1);

	//如果大于nthdays,说明还在当前年份
	if (daysCount > nthdays) {
		return TheNthDaysAfter(new_date, daysCount - nthdays); 
	}
	daysCount -= nthdays; //负数
	int &y = new_date.year;

	while(true) {
		--y;
		if (IsLeapYear(y) && daysCount + LEAP_YEAR < 0)
			nthdays += LEAP_YEAR;
		else if (daysCount + NORMAL_YEAR < 0)
			nthdays += NORMAL_YEAR;
		else
			break;
	}
	//将时间天数从距年底的天数转化成从年初的天数
	if (IsLeapYear(y))
		daysCount = LEAP_YEAR + daysCount;
	else
		daysCount = NORMAL_YEAR + daysCount;
	return TheNthDaysAfter(new_date, daysCount);
}

void
swap(Date d1, Date d2) {
	swap<int>(d1.year, d2.year);
	swap<int>(d1.month, d2.month);
	swap<int>(d1.day, d2.day);
}

int 
DateSpan(Date d1, Date d2) {
	if (d2 < d1) {
		swap(d1, d2);
	}

	int daysCount = 0;
	for (int y = d1.year; y < d2.year; ++y) {
		if (IsLeapYear(y))
			daysCount += LEAP_YEAR;
		else
			daysCount += NORMAL_YEAR;
	}

	return daysCount + TheNthDayOfYear(d2) - TheNthDayOfYear(d1);
}

int
main(int argc, char *argv[]) {
	Date d(2013, 1, 2);

	cout << STR(TheNthDayOfYear) << ":" << TheNthDayOfYear(d) << endl;

	cout << STR(TheNthDaysAfter) << ":" << TheNthDaysAfter(d, 2) << endl;

	cout << STR(TheNthDayBefore) << ":" << TheNthDayBefore(d, 2) << endl;

	Date d1(2013, 6, 1);
	Date d2(2013, 6, 1);
	cout << STR(DateSpan) << ":" << DateSpan(d1, d2) << endl;
	return 0;
}
